//===--- CheckSequenceInstance.swift.gyb ----------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

%{
from gyb_stdlib_unittest_support import TRACE, stackTrace, trace
}%

import StdlibUnittest

// Generate two overloads: one for Array (which will get
// picked up when the caller passes a literal), and another that
// accepts any appropriate Collection type.
% for genericParam, Element, Expected in zip(
%   ('Expected: Collection', 'Element'),
%   ('Expected.Iterator.Element', 'Element'),
%   ('Expected', 'Array<Element>')):

public func checkIterator<
  ${genericParam}, I : IteratorProtocol
>(
  _ expected: ${Expected},
  _ iterator: I,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
  sameValue: (${Element}, ${Element}) -> Bool
) where I.Element == ${Element} {
  // Copying a `IteratorProtocol` is allowed.
  var mutableGen = iterator
  var actual: [${Element}] = []
  while let e = mutableGen.next() {
    actual.append(e)
  }
  expectEqualSequence(
    expected, actual, ${trace}, sameValue: sameValue)

  // Having returned `.None` once, a `IteratorProtocol` should not generate
  // more elements.
  for _ in 0..<10 {
    expectNil(mutableGen.next(), ${trace})
  }
}

public func checkIterator<
  ${genericParam}, I : IteratorProtocol
>(
  _ expected: ${Expected},
  _ iterator: I,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) where I.Element == ${Element}, ${Element} : Equatable {
  checkIterator(
    expected, iterator, ${trace}, showFrame: false,
    resiliencyChecks: resiliencyChecks
  ) { $0 == $1 }
}

public func checkSequence<
  ${genericParam}, S : Sequence
>(
  _ expected: ${Expected},
  _ sequence: S,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
  sameValue: (${Element}, ${Element}) -> Bool
) where S.Iterator.Element == ${Element} {
  let expectedCount: Int = numericCast(expected.count)
  checkIterator(
    expected, sequence.makeIterator(), ${trace},
    resiliencyChecks: resiliencyChecks,
    sameValue: sameValue)

  expectGE(
    expectedCount, sequence.underestimatedCount, ${trace})

  // Test `_copyContents(initializing:)` if we can do so without destroying the
  // sequence.
  _ = sequence._preprocessingPass { () -> Void in
    var count = 0
    for _ in sequence { count += 1 }
    let buf = UnsafeMutablePointer<S.Iterator.Element>.allocate(capacity: count)
    let end = sequence._copyContents(initializing: buf)
    expectTrue(end == buf + count, "_copyContents returned the wrong value")
    var j = expected.startIndex
    for i in 0..<(end - buf) {
      expectTrue(sameValue(expected[j], buf[i]))
      j = expected.index(after: j)
    }
    buf.deinitialize(count: end - buf)
    buf.deallocate(capacity: count)
  }

  // Test `_copyToContiguousArray()` if we can do so
  // without destroying the sequence.
  _ = sequence._preprocessingPass { () -> Void in
    let copy = sequence._copyToContiguousArray()
    expectEqualSequence(expected, copy, ${trace}, sameValue: sameValue)
  }
}

public func checkSequence<
  ${genericParam}, S : Sequence
>(
  _ expected: ${Expected},
  _ sequence: S,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) where
  S.Iterator.Element == ${Element},
  S.Iterator.Element : Equatable {

  checkSequence(
    expected, sequence, ${trace}, showFrame: false,
    resiliencyChecks: resiliencyChecks
  ) { $0 == $1 }
}

% end

